/**
 *    Copyright 2006  <a href='mailto:rahul.thakur.xdev@gmail.com'>Rahul Thakur</a>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.continuum.ui.views;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.continuum.Activator;
import org.apache.continuum.internal.ConnectionProfileManager;
import org.apache.continuum.internal.model.BuildDefinitionAdapter;
import org.apache.continuum.internal.model.GroupAdapter;
import org.apache.continuum.internal.model.ProjectAdapter;
import org.apache.continuum.model.ConnectionProfile;
import org.apache.maven.continuum.xmlrpc.client.ContinuumXmlRpcClient;
import org.apache.maven.continuum.xmlrpc.project.BuildDefinition;
import org.apache.maven.continuum.xmlrpc.project.ProjectGroupSummary;
import org.apache.maven.continuum.xmlrpc.project.ProjectSummary;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.actions.ActionFactory;

/**
 * Controller entity of the MVC paradigm.
 * <p>
 * This renders the Project view.
 *
 * @author <a href='mailto:rahul.thakur.xdev@gmail.com'>Rahul Thakur</a>
 */
public class ProjectListViewer extends TreeViewer {

	/**
	 * Array of Table headers for the Category Document view.
	 */
	// private static ColumnHeaders [] headers = ColumnHeaders.values ();
	// View that is rendered by this viewer.
	private ProjectsView view;

	/**
	 * Create an instance of table-based {@link ProjectListViewer}.
	 *
	 * @param view
	 *            {@link Composite} parent to use for creating this viewer.
	 * @param treeTable
	 *            set of SWT.* options that could be used for styling up this
	 *            viewer.
	 */
	public ProjectListViewer(ProjectsView view, Tree treeTable) {
		super(treeTable);
		this.view = view;
		setContentProvider(new ViewContentProvider());
		setLabelProvider(new LabelProvider());
		// No input initially.
		setInput("ROOT");
		IActionBars actionBars = view.getViewSite().getActionBars();
		// FIXME: Add appropriate action handler here
		actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(),
				new NewConnectionAction(this));
	}

	// ------------------------------------------------------------------------
	// Content Provider Implementation for the viewer.
	// ------------------------------------------------------------------------

	public class ViewContentProvider implements ITreeContentProvider {

		/**
		 * TODO: Review this implementation.
		 */
		public Object[] getElements(Object elt) {
			return getChildren(elt);
		}

		public void dispose() {
			// TODO Auto-generated method stub

		}

		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
			// TODO Auto-generated method stub
			System.err.println("ViewContentProvider.inputChanged()");
		}

		/**
		 * @param elt
		 *            Parent Element.
		 */
		public Object[] getChildren(Object elt) {
			try {
				if (elt instanceof ConnectionProfile) {
					ConnectionProfile cp = (ConnectionProfile) elt;
					// Obtain groups for this connection profile
					String url = cp.getConnectionUrl();
					ContinuumXmlRpcClient client = new ContinuumXmlRpcClient(new URL(url), cp.getUsername(), cp.getPassword());
					List<ProjectGroupSummary> groups = client.getAllProjectGroups();
					GroupAdapter[] adapters = new GroupAdapter[groups.size()];
					for (int i = 0; i < groups.size(); i++) {
						adapters[i] = new GroupAdapter(groups.get(i), url);
					}
					return adapters;
				}

				if (elt instanceof GroupAdapter) {
					// building a concatenation of projects and builds
					GroupAdapter gAdapter = (GroupAdapter) elt;
					List<BuildDefinition> gBuilds = gAdapter.getBuildDefinitions();
					
					if (gBuilds == null) {
						List<ConnectionProfile> list = ConnectionProfileManager.loadConnectionProfiles();
						for (ConnectionProfile each : list) {
							if (each.getConnectionUrl().equals(gAdapter.getContiuumUrl())) {
								ContinuumXmlRpcClient client = new ContinuumXmlRpcClient(new URL(each.getConnectionUrl(), each.getUsername(), each.getPassword()));
    							gBuilds = client.getBuildDefinitionsForProjectGroup(gAdapter.getGroup().getId());
								gAdapter.setBuildDefinitions(gBuilds);
							}
						}
					}
					
					List<ProjectSummary> projects = gAdapter.getProjects();
					if (projects == null) {
						List<ConnectionProfile> list = ConnectionProfileManager.loadConnectionProfiles();
						for (ConnectionProfile each : list) {
							if (each.getConnectionUrl().equals(gAdapter.getContiuumUrl())) {
								ContinuumXmlRpcClient client = new ContinuumXmlRpcClient(new URL(each.getConnectionUrl(), each.getUsername(), each.getPassword()));
								projects = client.getProjects(gAdapter.getGroup().getId());
								gAdapter.setProjects(projects);
							}
						}
					}
					IAdaptable result[] = new IAdaptable[gBuilds.size() + projects.size()];
					// we return BuildAdapter[]
					for (int i = 0; i < projects.size(); i++) {
						result[i] = new ProjectAdapter(projects.get(i), gAdapter.getContiuumUrl());
					}
					for (int i = 0; i < gBuilds.size(); i++) {
						result[i + projects.size()] = new BuildDefinitionAdapter(gBuilds.get(i));
					}
					return result;
				}


				if (elt instanceof ProjectAdapter) {
					ProjectAdapter pAdapter = (ProjectAdapter) elt;
					List<BuildDefinition> builds = pAdapter
							.getBuildDefinitions();
					if (builds == null) {
						List<ConnectionProfile> list = ConnectionProfileManager.loadConnectionProfiles();
						for (ConnectionProfile each : list) {
							if (each.getConnectionUrl().equals(pAdapter.getContiuumUrl())) {
								ContinuumXmlRpcClient client = new ContinuumXmlRpcClient(new URL(each.getConnectionUrl(), each.getUsername(), each.getPassword()));
								builds = client.getBuildDefinitionsForProject(pAdapter.getProject().getId());
								pAdapter.setBuildDefinitions(builds);
							}
						}
					}
					// we return BuildAdapter[]
					BuildDefinitionAdapter[] ba = new BuildDefinitionAdapter[builds.size()];
					for (int i = 0; i < ba.length; i++) {
						ba[i] = new BuildDefinitionAdapter((BuildDefinition) builds.get(i));
					}
					return ba;
				}
				// Else, we are creating view contents afresh
				System.err.println("Loading Connection Profiles...");
				List<ConnectionProfile> list = new ArrayList<ConnectionProfile>();
				list = ConnectionProfileManager.loadConnectionProfiles();
				return list.toArray();
			} catch (Exception e) {
				// TODO: better error reporting.
				Activator.getDefault().getLog().log(
						new Status(IStatus.ERROR, Activator.PLUGIN_ID, -1, e
								.getLocalizedMessage(), e));
			}
			return null;
		}

		public Object getParent(Object elt) {
			// TODO: Obtain parent node based class of passed in element.
			System.err.println("ViewContentProvider.getParent()");
			return null;
		}

		/**
		 * Determines if a node element in the viewer has children.
		 *
		 * @return <code>true</code> if a selected node element had children.
		 */
		public boolean hasChildren(Object elt) {
			if (elt instanceof ConnectionProfile) {
				ConnectionProfile cpd = (ConnectionProfile) elt;
				try {
					// Obtain projects for this connection profile
					String url = cpd.getConnectionUrl();
					ContinuumXmlRpcClient client = new ContinuumXmlRpcClient(
							new URL(url), cpd.getUsername(), cpd.getPassword());
					return (client.getAllProjectGroups().size() > 0);
				} catch (Exception e) {
					MessageDialog.openError(view.getSite().getShell(), "Error",
							e.getMessage());
					return false;
				}
			}

			if (elt instanceof ProjectAdapter) {
				return true;
			}

			if (elt instanceof GroupAdapter) {
				return true;
			}

			return false;
		}

	}

	// ------------------------------------------------------------------------
	// Label Provider Implementation for the viewer.
	// ------------------------------------------------------------------------

	public class LabelProvider implements ITableLabelProvider {

		public Image getColumnImage(Object element, int columnIndex) {
			// TODO Return proper image.
			return null;
		}

		public String getColumnText(Object elt, int colIdx) {
			if (elt instanceof ConnectionProfile) {
				ConnectionProfile cpd = (ConnectionProfile) elt;
				if (colIdx == 0)
					return cpd.getId();
			}

			// FIXME : Build column labels appropriately, currently testing
			// only.
			if (elt instanceof ProjectAdapter) {
				ProjectSummary p = ((ProjectAdapter) elt).getProject();
				switch (colIdx) {
					case 0 : return p.getName();
					case 1 : return Integer.toString(p.getState());
					case 2 : return p.getGroupId();
					case 3 : return p.getArtifactId();
				}
			}

			if (elt instanceof GroupAdapter) {
				ProjectGroupSummary bd = ((GroupAdapter) elt)
						.getGroup();
				if (colIdx == 0) {
					return bd.getName();
				}
			}


			if (elt instanceof BuildDefinitionAdapter) {
				BuildDefinition bd = ((BuildDefinitionAdapter) elt)
						.getBuildDefinition();
				if (colIdx == 0)
					return Integer.toString(bd.getId());
				if (colIdx == 1)
					return bd.getGoals();
				if (colIdx == 2)
					return bd.getArguments();
				if (colIdx == 3)
					return (null != bd.getSchedule()) ? bd.getSchedule()
							.getName() : "";
			}

			return "";
		}

		public void addListener(ILabelProviderListener listener) {
			// TODO Auto-generated method stub

		}

		public void dispose() {
			// TODO Auto-generated method stub

		}

		public boolean isLabelProperty(Object element, String property) {
			// TODO Auto-generated method stub
			return false;
		}

		public void removeListener(ILabelProviderListener listener) {
			// TODO Auto-generated method stub

		}

	}
}
